package org.c41.math;

import org.c41.util.Check;

public class Complex {

	public static final Complex ZERO = new Complex(Rational.ZERO,Rational.ZERO);
	public static final Complex ONE = new Complex(Rational.ONE,Rational.ZERO);
	
	private Rational real;
	private Rational imag;
	
	public Complex(Rational real, Rational imag){
		Check.notNull(real);
		Check.notNull(imag);
		m_assign(real, imag);
	}
	
	public Complex(long real, long imag){
		m_assign(new Rational(real), new Rational(imag));
	}
	
	public Complex(Rational real){
		Check.notNull(real);
		m_assign(real, Rational.ZERO);
	}
	
	public Complex(long real){
		m_assign(new Rational(real), Rational.ZERO);
	}
	
	private void m_assign(Rational real, Rational imag){
		this.real=real;
		this.imag=imag;
	}
	
	public Rational getReal(){
		return real;
	}
	
	public Rational getImag(){
		return imag;
	}
	
	public Complex add(Complex complex){
		return new Complex(this.real.add(complex.real), this.imag.add(complex.imag));
	}
	
	public Complex subtract(Complex complex){
		return new Complex(this.real.subtract(complex.real), this.imag.subtract(complex.imag));
	}
	
	public Complex multiply(Complex complex){
		Rational real = this.real.multiply(complex.real).subtract(this.imag.multiply(complex.imag));
		Rational imag = this.real.multiply(complex.imag).add(this.imag.multiply(complex.real));
		return new Complex(real, imag);
	}
	
	public Complex reciprocal(){
		Rational de = this.real.pow(2).add(this.imag.pow(2));
		return new Complex(this.real.divide(de), this.imag.divide(de).negate());
	}
	
	public Complex divide(Complex complex){
		return this.multiply(complex.reciprocal());
	}
	
	@Override
	public boolean equals(Object obj){
		if(!(obj instanceof Complex)){
			return false;
		}
		Complex complex = (Complex)obj;
		return this.real.equals(complex.real)&&this.imag.equals(complex.imag);
	}
	
	@Override
	public int hashCode(){
		return this.real.hashCode()*this.imag.hashCode()*this.imag.hashCode();
	}
	
	public Complex negate(){
		return new Complex(real.negate(),imag);
	}
	
}
